﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Web;
using Vit.Common.Extensions;

namespace Vit.Web.Helpers
{
    public class MenuHelper
    {
        public static IEnumerable<XElement> GetCurrentMenu()
        {
            string groupName = HttpContext.Current.Session["CurrentMenuName"] as string;
            if (string.IsNullOrEmpty(groupName))
                groupName = "default";

            return GetMenu(groupName);
        }

        public static IEnumerable<XElement> GetMenu(string groupName)
        {
            var menuGroup = GetMenuGroup(groupName);
            if (menuGroup != null)
                return menuGroup.Elements();

            return null;
        }

        public static XElement GetMenuGroup(string groupName)
        {
            XDocument doc = LoadMenuConfiguration();
            return doc.Root.XPathSelectElement(string.Format("group[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='{0}']", groupName.ToLower()));
        }

        public static XElement GetTopMenu(XElement child)
        {
            XElement parent = child;
            while (parent != null && parent.Parent != null && parent.Parent.Name != "group")
            {
                parent = parent.Parent;
            }
            return parent;
        }

        public static int GetMenuItemIndex(XElement ele)
        {
            XElement parent = ele.Parent;
            if (parent != null)
            {
                var eles = parent.Elements("menu");
                int i = 0;
                foreach (var el in eles)
                {
                    if (Equals(el, ele))
                        return i;
                    i++;
                }
            }
            return -1;
        }

        public static bool Equals(XElement a, XElement b)
        {
            string aname = a.AttributeValue("name", "");
            string aurl = a.AttributeValue("url", "");
            string bname = b.AttributeValue("name", "");
            string burl = b.AttributeValue("url", "");

            return !string.IsNullOrEmpty(aname) && !string.IsNullOrEmpty(aurl) && aname.Equals(bname) && aurl.Equals(burl);
        }

        public static bool HasChildren(XElement ele)
        {
            return ele.Elements("menu").Any(o => o.AttributeValue<bool>("isVirtual", false) == false);
        }

        public static IEnumerable<XElement> GetChildrenMenu(XElement ele)
        {
            return ele.Elements("menu").Where(o => o.AttributeValue<bool>("isVirtual", false) == false);
        }

        public static XElement GetCurrentUserFavorites()
        {
            // todo: add user's favorites menu
            return null;
        }

        public static XElement GetSelectedMenu(RouteData route, IEnumerable<XElement> menu)
        {
            string url = HttpContext.Current.Request.Path;

            string key = string.Format("URL-MENU:{0}", url);
            if (HttpContext.Current.Cache[key] != null)
                return HttpContext.Current.Cache[key] as XElement;

            XElement sm = GetSelectedMenu(url, menu);
            if (sm == null)
            {
                sm = GetSelectedMenu(string.Format("{0}/{1}", url, route.Values["action"]), menu);
                if (sm == null)
                    sm = GetSelectedMenu(url.Substring(0, url.LastIndexOf('/')), menu);
                if (sm == null)
                    sm = GetSelectedMenu(string.Format("{0}/{1}", route.Values["controller"], route.Values["action"]), menu);
            }

            if (sm != null)
                HttpContext.Current.Cache.Insert(key, sm);

            return sm;
        }

        public static XElement GetSelectedMenu(string url, IEnumerable<XElement> menu)
        {
            if (menu == null)
                return null;

            XElement smenu = null;
            foreach (XElement ele in menu)
            {
                smenu = ele.XPathSelectElement(string.Format("//menu[translate(@url,'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')='{0}']", url.ToLower()));
                if (smenu != null)
                    break;
            }

            return smenu;
        }

        public static XElement GetMenuParent(XElement ele)
        {
            if (ele == null)
                return null;

            while (ele.AttributeValue("isVirtual", false) && ele.Parent != null)
            {
                ele = ele.Parent;
            }
            return ele;
        }

        public static string RenderCrumblePath(XElement ele)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(string.Format("> <span>{0}</span>", ele.AttributeValue("caption", ele.AttributeValue("name", "unknown"))));
            XElement parent = ele.Parent;
            while (parent != null)
            {
                if (parent.Name == "group")
                    break;

                sb.Insert(0, string.Format("> <a href='{0}' title='{1}'>{1}</a>",
                    parent.AttributeValue("url", "javascript:void();"),
                    parent.AttributeValue("caption", parent.AttributeValue("name", "unknown"))));

                parent = parent.Parent;
            }
            return sb.ToString().TrimStart('>');
        }

        public static string ReplaceWithRouteData(string url)
        {
            if (url.IndexOf("route") >= 0)
            {
                HttpContextBase context = new HttpContextWrapper(HttpContext.Current);
                RouteData routeData = RouteTable.Routes.GetRouteData(context);
                Dictionary<string, string> replacements = new Dictionary<string, string>();
                foreach (var kvp in routeData.Values)
                    replacements.Add(string.Format("{{route:{0}}}", kvp.Key), kvp.Value.ToString());

                string replacedUrl = url.Replace(replacements);
                return replacedUrl.Replace("\"", "&quto;");
            }
            else
                return url;
        }

        private static XDocument LoadMenuConfiguration()
        {
            XDocument doc = HttpContext.Current.Cache["XMenu"] as XDocument;
            if (doc == null)
            {
                string path = HttpContext.Current.Server.MapPath("~/Configuration/menu.config");
                if (System.IO.File.Exists(path))
                {
                    doc = XDocument.Load(path);
                    HttpContext.Current.Cache.Insert("XMenu", doc);
                }
            }
            return doc;
        }
    }
}
